package com.iflytek.jzcpx.procuracy.ocr.common.helper;

import javax.imageio.ImageIO;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.jzcpx.procuracy.ocr.common.constant.Constants.PDFCompose;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.Cell;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.Char;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.OcrResult;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.Page;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.PdfImage;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.Rect;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.Sent;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.Table;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.TaskResult;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.TextRegion;
import com.iflytek.jzcpx.procuracy.tools.ocr.pdf.Textline;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfNumber;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.parser.PdfImageObject;
import com.lowagie.text.BadElementException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfGState;
import com.lowagie.text.pdf.PdfWriter;
import com.xiaoleilu.hutool.util.ObjectUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 合成 双层 PDF: 利用原始图片以及图片对应的识别出的ocr json结果 合成双层PDF文件
 *
 * @author z4463
 */
@Component
public class PdfComposeUtil {

    private static final String DEFAULT_OCR_VERSION = PDFCompose.NEW_OCR_VERSION;

    private static final Logger logger = LoggerFactory.getLogger(PdfComposeUtil.class);

    /**
     * 空格
     */
    private static final String SPACE_CHAR = " ";

    /**
     * 使用的字体
     */
    private static final BaseFont bfChinese = getBaseFont();
    /**
     * 单页PDF的压缩比例
     */
    private static float factor;
    private static int pdfSize;

    @Value("${factor:0.8}")
    public void setFactorValue(float factorValue){
        factor = factorValue;
    }
    @Value("${pdfSize:512000}")
    public void setPdfSizeValue(int pdfSizeValue){
        pdfSize = pdfSizeValue;
    }
    /**
     * @param imageByte 图片文件 (字节流)
     * @param ocrJson   图片对应的ocr识别数据 (json格式)
     * @return PDF文件 (字节流)
     * @throws Exception
     * @description 将图片与 图片对应的ocr识别数据合成双层PDF文件
     * @author zyzhang15
     * @create 2018年2月26日上午8:51:08
     * @version 1.0
     */
    public byte[] handleCompose(byte[] imageByte, String ocrJson) throws Exception {

        if (imageByte == null || imageByte.length == 0) {
            logger.error("构建PDF文件失败! 图像数据为空!!");
            return null;
        }

        if (StringUtils.isEmpty(ocrJson)) {
            logger.error("构建PDF文件失败! ocrJson数据为空!!");
            return null;
        }

        // 根据ocr数据修正图片
        PdfImage pdfData = getCurrentionPDFData(imageByte, ocrJson);
        // 定义文档的尺寸
        String picRectangle = pdfData.getImageCurrentionWidth() + SPACE_CHAR + pdfData.getImageCurrentionHeight();
        // 新建文档

        Document document = new Document(PageSize.getRectangle(picRectangle));
        // 输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageByte.length);
        // 新建书写器
        PdfWriter writer = PdfWriter.getInstance(document, outputStream);

        writer.setSpaceCharRatio(PdfWriter.SPACE_CHAR_RATIO_DEFAULT);
        writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
        document.open();
        try {
            // 获取画板
            PdfContentByte canvas = writer.getDirectContent();
            // 将原始图片作为pdf背景 写入 pdf
            canvas.addImage(pdfData.getImage());
            // 设置文字透明度
            PdfGState pdfGState = new PdfGState();
            pdfGState.setFillOpacity(0f);
            canvas.setGState(pdfGState);
            // 向PDF写入文字
            handlePage(canvas, pdfData);
        } finally {
            document.close();
            outputStream.close();
        }

        byte[] pdfByte = outputStream.toByteArray();
        if(ObjectUtil.isNotNull(pdfByte)){
            try{
                pdfByte = manipulatePdf(pdfByte);
            }catch (Exception e){
                logger.info("pdf文件流压缩出错");
            }
        }

        return pdfByte;

    }

    /**
     * @param ocrJson
     * @return
     * @throws IOException
     * @description 将ocr JsonString 转换为OcrResult对象
     * @author zyzhang15
     * @create 2018年2月25日下午3:20:22
     * @version 1.0
     */
    public static OcrResult getOcrResult(String ocrJson) {
        // 将原始json数据中 List为null 的对象删除 ,将 String为null的对象转为空
        String pureJson = JSON.toJSONString(JSON.parseObject(ocrJson));
        OcrResult ocrResult = JSONObject.parseObject(pureJson, OcrResult.class);
        return ocrResult;
    }

    /**
     * 把pic对应的ocrResult信息写入 pdf
     *
     * @param canvas 指定页面的 canvas
     * @throws IOException
     * @throws DocumentException
     */
    private void handlePage(PdfContentByte canvas, PdfImage pdfData) {

        OcrResult ocrResult = pdfData.getOcrResult();

        TaskResult taskResult = ocrResult.getTaskResult();
        List<Page> pageList = taskResult.getPage();
        //过滤空page对象
        pageList = pageList.stream().filter(item -> null != item).collect(Collectors.toList());
        // 处理页面信息 (目前实际只有一页,整个逻辑也是按照一页处理)
        for (Page page : pageList) {
            // 处理文字区域
            for (TextRegion textRegion : page.getTextRegion()) {
                List<Textline> textlines = textRegion.getTextline();
                Collections.sort(textlines, (a, b) -> a.getRect().getY().compareTo(b.getRect().getY()));
                List<List<Textline>> resultGroup = byGroup(textlines, (t1, t2) -> {
                    int mutipile = 4;
                    int offset = Math.abs(t1.getRect().getY() - t2.getRect().getY());
                    if (offset < (t1.getRect().h) / mutipile && offset < (t2.getRect().h / mutipile)) {
                        return 0;
                    } else {
                        return 1;
                    }
                });
                for (List<Textline> textlines1 : resultGroup) {
                    Collections.sort(textlines1, (a, b) -> a.getRect().getX().compareTo(b.getRect().getX()));
                    if (textlines1.size() > 1) {
                        // logger.info("the same line");
                    }
                    for (Textline textline : textlines1) {
                        handleTextLine(canvas, pdfData, textline);
                    }
                }
            }
            // 处理表格区域
            for (Table table : page.getTable()) {
                for (Cell cell : table.getCell()) {
                    for (Textline textline : cell.getTextline()) {
                        handleTextLine(canvas, pdfData, textline);
                    }
                }
            }
        }
    }

    /**
     * 根据传入的比较器进行集合的分组
     *
     * @param data 需要分组的元素集合
     * @param c    传入的比较器
     * @param <T>  元素
     * @return 返回分组后的集合列表
     */
    private static <T> List<List<T>> byGroup(Collection<T> data, Comparator<? super T> c) {
        //方法上使用泛型 记得在返回值前加<T>
        List<List<T>> result = new ArrayList<>();
        for (T t : data) {//1.循环取出集合中的每个元素
            boolean isSameGroup = false;//2.标志为不是同组
            for (List<T> aResult : result) {//4.循环查找当前元素是否属于某个已创建的组
                if (c.compare(t, aResult.get(0)) == 0) {//aResult.get(0)表示：只要当前元素和某个组的第一个元素通过比较器比较相等则属于该组
                    isSameGroup = true;//5.查询到当前元素属于某个组则设置标志位，不让其创键新组
                    aResult.add(t);//6.把当前元素添加到当前组
                    break;
                }
            }
            if (!isSameGroup) {//3.不属于任何组的则创建一个新组，并把元素添加到该组
                // 创建
                List<T> innerList = new ArrayList();
                innerList.add(t);
                result.add(innerList);
            }
        }
        return result;
    }

    /**
     * 打印每一行文字 (按每一个字定位打印)
     *
     * @param textline
     * @param canvas
     * @throws DocumentException
     * @throws IOException
     */
    private void handleTextLine(PdfContentByte canvas, PdfImage pdfData, Textline textline) {

        // ocr识别的数据比较规范,Rect为空时说明 整个textline域都为空,则不再处理本行.
        if (textline.getRect() == null) {
            return;
        }
        if (CollectionUtils.isEmpty(textline.getSent())) {
            return;
        }
        // 目前ocrs引擎只能识别出文字是否是手写体,文本内容识别效果较差,暂时抛弃ocr手写体识别内容
        //        if (PDFCompose.OCR_HANDWRITE_TYPE.equals(textline.getType())) {
        //            return;
        //        }

        try {
            Float imageHeight = pdfData.getImageCurrentionHeight();
            Float imageWeight = pdfData.getImageCurrentionWidth();
            // 行最大高度作为文字字体的字号
            float fontSize = textline.getRect().h * 0.9f;
            Font font = new Font(bfChinese, fontSize, Font.NORMAL);
            switch (DEFAULT_OCR_VERSION) {
                case PDFCompose.NEW_OCR_VERSION:
                    handleWithNewProtocol(canvas, imageHeight, font, textline, imageWeight);
                    break;
                case PDFCompose.OLD_OCR_VERSION:
                    handleTextlineWithOldProtocol(canvas, imageHeight, font, textline);
                    break;
            }
        } catch (Exception ex) {
            logger.error("写入PDF 具体一行 时出现错误,行内容:{},错误信息:{}", textline.toString(), ex);
        }
    }

    /**
     * @param canvas
     * @param imageHeight
     * @param font
     * @description 之前1525以及之前版本的输出协议
     * @author zyzhang15
     * @create 2018年4月3日下午5:23:52
     * @version 1.0
     */
//    private void handleTextlineWithOldProtocol(PdfContentByte canvas, Float imageHeight, Font font, Textline textline) {
//        Font numFont = new Font(font.getBaseFont(), new Float(font.getSize() * 1.41), Font.NORMAL);
//        for (Sent sent : textline.getSent()) {
////            Phrase phrase = new Phrase(sent.getValue(), font);
//            for (Char s : sent.getChar()) {
//                ColumnText columnText = new ColumnText(canvas);
//                String txt = s.getValue();
//                Rect rect = s.getRect();
//                int x = rect.x;
//                int y = rect.y;
//                int h = rect.h;
//                /**
//                 * f_y 坐标的如此计算是因为ocr原始信息的定位的坐标原点是<左上>  itextpdf定位的坐标原点是<左下>
//                 */
//                float xPoint = x;
//                float yPoint = imageHeight - y - h;
//                float xrPoint = x+h;
//                float yrPoint = imageHeight - rect.getTr_point().y - h;
//                if (",".equals(txt)) {
//                    txt = "，";
//                }
//                if (":".equals(txt)) {
//                    txt = "：";
//                }
//                if("(".equals(txt)){
//                    txt = "（";
//                }
//                if(")".equals(txt)){
//                    txt = "）";
//                }
//
//                Phrase phrase;
//                if (Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "：", "，", "-", "（", "）", "“", "”","、").contains(txt)) {
//                    phrase = new Phrase(txt, numFont);
//                } else {
//                    phrase = new Phrase(txt, font);
//                }
////                Paragraph paragraph = new Paragraph(phrase);
////                columnText.setSimpleColumn(xPoint, yPoint, xrPoint, yrPoint);
////                paragraph.setAlignment(Paragraph.ALIGN_JUSTIFIED);
////                columnText.addElement(paragraph);
////                try {
////                    columnText.go();
////                } catch (DocumentException e) {
////                    e.printStackTrace();
////                }
//                ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, xPoint, yPoint, 0);
//            }
//        }
//    }

    /**
     * @param canvas
     * @param imageHeight
     * @param font
     * @description 之前1525以及之前版本的输出协议
     * @author zyzhang15
     * @create 2018年4月3日下午5:23:52
     * @version 1.0
     */
    private static void handleTextlineWithOldProtocol(PdfContentByte canvas, Float imageHeight, Font font, Textline textline) {
        for (Sent sent : textline.getSent()) {
//            Phrase phrase = new Phrase(sent.getValue(), font);
            for (Char s : sent.getChar()) {
                ColumnText columnText = new ColumnText(canvas);
                String txt = s.getValue();
                Rect rect = s.getRect();
                int x = rect.x;
                int y = rect.y;
                int h = rect.h;
                /**
                 * f_y 坐标的如此计算是因为ocr原始信息的定位的坐标原点是<左上>  itextpdf定位的坐标原点是<左下>
                 */
                float xPoint = x;
                float yPoint = imageHeight - y - h;
                float xrPoint = x + h;
                float yrPoint = imageHeight - rect.getTr_point().y - h;
                Phrase phrase = new Phrase(txt, font);
                Paragraph paragraph = new Paragraph(phrase);
                columnText.setSimpleColumn(xPoint, yPoint, xrPoint, yrPoint);
                paragraph.setAlignment(Paragraph.ALIGN_JUSTIFIED_ALL);
                columnText.addElement(paragraph);
                try {
                    columnText.go();
                } catch (DocumentException e) {
                    e.printStackTrace();
                }
                ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, xPoint, yPoint, 0);
            }
        }
    }

    /**
     * @param canvas
     * @param imageHeight
     * @param font
     * @description 1622+ 版本的输出协议
     * @author zyzhang15
     * @create 2018年4月3日下午5:27:05
     * @version 1.0
     */
    private void handleWithNewProtocol(PdfContentByte canvas, Float imageHeight, Font font, Textline textline, Float imageWeight) {
        for (Sent sent : textline.getSent()) {
            //空白行过滤
            if (CollectionUtils.isEmpty(sent.getChar()) || StringUtils.isEmpty(sent.getValue())) {
                return;
            }
            //计算每个矩形的左上坐标以及矩形宽&高
            for (Char s : sent.getChar()) {
                Rect rect = s.getRect();
                //左上(x,y)
                rect.x = rect.tl_point.x;
                rect.y = rect.tl_point.y;

                // 底部左右两坐标x之差为W
                // 左边上下两坐标y之差为H
                rect.w = Math.abs(rect.br_point.x - rect.bl_point.x);
                rect.h = Math.abs(rect.bl_point.y - rect.tl_point.y);

                	/*if(font.getSize() > rect.w) {
                        font.setSize(rect.w);
                	}
                	if(font.getSize() < rect.w) {
                		rect.w=(int)font.getSize();
                	}*/
                //求宽度 高度 字体大小中最大值 保证复制 不带空格 选中高度小于字体高度形况
                	/*int max = (rect.w > rect.h) ? rect.w : rect.h;
                	max = (max > (int)font.getSize()) ? max : (int)font.getSize();
                	rect.w=max;
                	rect.h=max;
                	font.setSize(max);*/
            }
        }
        //        handleTextlineWithOldProtocol(canvas, imageHeight, font, textline);
        handleTextlineWithOldProtocolRectangle2(canvas, imageHeight, font, textline, imageWeight);
    }

    /**
     * @param pic     图片字节流
     * @param ocrJson ocrJson String
     * @return PdfData 对象
     * @throws BadElementException 图像数据异常(IO异常 或数据损坏)
     * @throws IOException
     * @description 修正图片并构建pdf对象
     * @author zyzhang15
     * @create 2018年2月25日下午3:44:27
     * @version 1.0
     */
    private PdfImage getCurrentionPDFData(byte[] pic, String ocrJson) throws IOException, BadElementException {

        // 获取ocr数据
        OcrResult ocrResult = getOcrResult(ocrJson);

        // 获取图片的被修正的角度值
        int rotation = (int) ocrResult.getTaskResult().getPage().get(0).getOrientation();
//        rotation=90;
        Image image = null;
        if (rotation != 0) {
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(pic);
            BufferedImage src = null;
            try {
//                ImageIO.read方法前，把jpg图片文件重写，防止图片的颜色空间（colorspace)为CMYK模式。导致了ImageIO.read()方法抛出异常
                src = ImageIO.read(byteArrayInputStream);
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            rotation = 360 - rotation;
            BufferedImage des1 = Rotate(src, rotation);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            try {
                ImageIO.write(des1, "png", byteArrayOutputStream);//写入流中
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            pic = byteArrayOutputStream.toByteArray();//转换成字节
            image = Image.getInstance(pic);
        }else {
            // 读取图片
            java.awt.Image imageAwt = Toolkit.getDefaultToolkit().createImage(pic);
            image = Image.getInstance(imageAwt,null);
        }
        //        Image image = TiffImage.getTiffImage(new RandomAccessFileOrArray(pic), 1);
//        image.setDpi(30,30);
        logger.info(
                "图片尺寸getPlainHeight: {}, getPlainWidth: {}, getScaledHeight: {}, getScaledWidth: {}, getHeight: {}, " +
                        "getWidth: {}",
                image.getPlainHeight(), image.getPlainWidth(), image.getScaledHeight(), image.getScaledWidth(),
                image.getHeight(), image.getWidth());
        image.scaleAbsoluteHeight(image.getPlainHeight());
        image.scaleAbsoluteWidth(image.getPlainWidth());
        image.setAbsolutePosition(0, 0);


        /*//仅旧版ocr数据可以做旋转矫正,新版协议改变,不能旋转
        switch (DEFAULT_OCR_VERSION) {
            case PDFCompose.OLD_OCR_VERSION:
                // 获取图片的被修正的角度值
                float rotation = getCurrentionRoration(ocrResult);
                image.setRotation(rotation);
                break;
            default:
                break;
        }*/


        // 构建PdfData数据
        PdfImage pdfData = new PdfImage();
        pdfData.setImage(image);
        pdfData.setOcrResult(ocrResult);
        pdfData.setIamgeOriginalHeight(image.getPlainHeight());
        pdfData.setIamgeOriginalWidth(image.getPlainWidth());
        pdfData.setImageCurrentionHeight(image.getScaledHeight());
        pdfData.setImageCurrentionWidth(image.getScaledWidth());

        return pdfData;
    }

    /**
     * @param ocrResult
     * @return
     * @description 获取图片被修正的角度
     * @author zyzhang15
     * @create 2018年3月21日下午4:32:15
     * @version 1.0
     */
    public static Float getCurrentionRoration(OcrResult ocrResult) {
        TaskResult taskResult = ocrResult.getTaskResult();
        Page page = null;
        boolean pageExist = taskResult.getPage() != null && taskResult.getPage().size() > 0;
        if (pageExist) {
            page = taskResult.getPage().get(0);

            return page.getAngle() == null ? 0f : page.getAngle().floatValue();
        }
        return 0f;
    }

    /**
     * @return
     * @description 初始化字体对象
     * @author zyzhang15
     * @create 2018年3月6日上午9:36:21
     * @version 1.0
     */
    private static BaseFont getBaseFont() {
        try {
            // 获取字体文件路径。但是ResourceUtil的功能过多，故不提供源码实现
            // String fontPath = ResourceUtil.copyJarFileToTemp("STSONG.TTF");
            String fontPath = "STSONG.TTF";
            return BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        } catch (Exception e) {
            logger.error("PDFComposeUtil 初始化失败,字体对象初始化失败 ,ERROR INFO:{}", e.toString());
        }
        return null;
    }
    private void handleTextlineWithOldProtocolRectangle2(PdfContentByte canvas, Float imageHeight, Font font, Textline textline, Float imageWeight) {
        for (Sent sent : textline.getSent()) {
            StringBuffer stringBuffer = new StringBuffer();
            float xlPoint = 0;
            float ylPoint = 0;
            float xrPoint = 0;
            float yrPoint = 0;
            float h = 0;
            float w = 0;
            ColumnText columnText = new ColumnText(canvas);
            stringBuffer.append(sent.getValue());
            //for (int i = 0; i < sent.getChar().size(); i++) {
            xlPoint = sent.getChar().get(0).getRect().getX();
            xrPoint = sent.getChar().get(sent.getChar().size() - 1).getRect().getX();
            ylPoint = sent.getChar().get(0).getRect().getY();
            yrPoint = sent.getChar().get(sent.getChar().size() - 1).getRect().getY();
            //            	h = sent.getChar().get(i).getRect().h;
            //}
            ArrayList<Rect> rects = (ArrayList<Rect>) sent.getChar().stream().map(Char::getRect)
                                                          .collect(Collectors.toList());
            h = (float) rects.stream().mapToDouble(Rect::getH).max().getAsDouble();
            int sumW = rects.get(rects.size() - 1).getBr_point().getX() - rects.get(0).getBl_point().getX();
            w = sumW / rects.size();
            font.setSize(w);
            Phrase phrase = new Phrase(stringBuffer.toString(), font);
            //Rectangle rect1 = new Rectangle(xlPoint, imageHeight - ylPoint- 2*h, xlPoint +sumW+h , imageHeight - yrPoint);
            columnText.setSimpleColumn(phrase, xlPoint, imageHeight - ylPoint - 2 * h, xlPoint + sumW,
                    imageHeight - yrPoint - 4 * h / 5, 0, Phrase.ALIGN_JUSTIFIED_ALL);
            try {
                columnText.go();
                this.drawRect(canvas);
            }
            catch (DocumentException e) {
                logger.error("双层pdf按行优化失败", e);
            }
        }
    }

    public void drawRect(PdfContentByte cb) {
        cb.saveState();
        cb.restoreState();
    }

    /**
     * 对图片进行旋转
     */
    public static BufferedImage Rotate(java.awt.Image src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        // 计算旋转后图片的尺寸
        java.awt.Rectangle rect_des = CalcRotatedSize(new java.awt.Rectangle(new Dimension(
                src_width, src_height)), angel);
        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();
        // 进行转换
        g2.translate((rect_des.width - src_width) / 2,
                (rect_des.height - src_height) / 2);
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

        g2.drawImage(src, null, null);
        return res;
    }

    /**
     *计算旋转后的图片
     */
    public static java.awt.Rectangle CalcRotatedSize(java.awt.Rectangle src, int angel) {
        // 如果旋转的角度大于90度做相应的转换
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }

        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);

        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_width));
        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_height));
        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }
    public static byte[] manipulatePdf(byte[] src) throws IOException, DocumentException, com.itextpdf.text.DocumentException {
        PdfName key = new PdfName("ITXT_SpecialId");
        PdfName value = new PdfName("123456789");
        // 读取pdf文件
        PdfReader reader = new PdfReader(src);
        int n = reader.getXrefSize();
        PdfObject object;
        PRStream stream;
        // Look for image and manipulate image stream
        for (int i = 0; i < n; i++) {
            object = reader.getPdfObject(i);
            PdfObject pdfObject = reader.getPdfObject(i);
            if (object == null || !object.isStream())
                continue;
            stream = (PRStream) object;
            PdfObject pdfsubtype = stream.get(PdfName.SUBTYPE);

            if (pdfsubtype != null && pdfsubtype.toString().equals(PdfName.IMAGE.toString())) {
                PdfImageObject image = new PdfImageObject(stream);
                BufferedImage bi = image.getBufferedImage();
                if (bi == null) continue;
                int width = (int) (bi.getWidth() * factor);
                int height = (int) (bi.getHeight() * factor);
                BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                AffineTransform at = AffineTransform.getScaleInstance(factor, factor);
                Graphics2D g = img.createGraphics();
                g.drawRenderedImage(bi, at);
                ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
                //判断文件流的大小，超过500k的才进行压缩，否则不进行压缩
                if(img.getData().getDataBuffer().getSize()>pdfSize){
                    ImageIO.write(img, "JPG", imgBytes);
                    stream.clear();
                    stream.setData(imgBytes.toByteArray(), false, PRStream.BEST_COMPRESSION);
                    stream.put(PdfName.TYPE, PdfName.XOBJECT);
                    stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
                    stream.put(key, value);
                    stream.put(PdfName.FILTER, PdfName.DCTDECODE);
                    stream.put(PdfName.WIDTH, new PdfNumber(width));
                    stream.put(PdfName.HEIGHT, new PdfNumber(height));
                    stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
                    stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
                }else {
                    ImageIO.write(img, "JPG", imgBytes);
                }
            }
        }
        // Save altered PDF
        ByteArrayOutputStream dest = new ByteArrayOutputStream();
        PdfStamper stamper = new PdfStamper(reader, dest);
        stamper.close();
        reader.close();
        return dest.toByteArray();
    }

}
